package com.yingwei.util;

import javax.swing.*;
import javax.swing.SpringLayout;
import java.awt.*;

/**
 * A 1.4 file that provides utility methods for creating form- or grid-style
 * layouts with SpringLayout. These utilities are used by several programs, such
 * as SpringBox and SpringCompactGrid.
 */
public class SpringUtilities
{
    /**
     * A debugging utility that prints to stdout the component's minimum,
     * preferred, and maximum sizes.
     */
    public static void printSizes(Component c)
    {
	System.out.println("minimumSize = " + c.getMinimumSize());
	System.out.println("preferredSize = " + c.getPreferredSize());
	System.out.println("maximumSize = " + c.getMaximumSize());
    }

    /**
     * Aligns the first <code>rows</code> * <code>cols</code> components of
     * <code>parent</code> in a grid. Each component is as big as the maximum
     * preferred width and height of the components. The parent is made just big
     * enough to fit them all.
     * 
     * @param rows
     *            number of rows
     * @param cols
     *            number of columns
     * @param initialX
     *            x location to start the grid at
     * @param initialY
     *            y location to start the grid at
     * @param xPad
     *            x padding between cells
     * @param yPad
     *            y padding between cells
     */
    public static void makeGrid(Container parent, int rows, int cols,
	    int initialX, int initialY, int xPad, int yPad)
    {
	SpringLayout layout;
	try
	{
	    layout = (SpringLayout) parent.getLayout();
	}
	catch (ClassCastException exc)
	{
	    System.err
		    .println("The first argument to makeGrid must use SpringLayout.");
	    return;
	}

	Spring xPadSpring = Spring.constant(xPad);
	Spring yPadSpring = Spring.constant(yPad);
	Spring initialXSpring = Spring.constant(initialX);
	Spring initialYSpring = Spring.constant(initialY);
	int max = rows * cols;

	// Calculate Springs that are the max of the width/height so that all
	// cells have the same size.
	Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0))
		.getWidth();
	Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0))
		.getWidth();
	for (int i = 1; i < max; i++)
	{
	    SpringLayout.Constraints cons = layout.getConstraints(parent
		    .getComponent(i));

	    maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth());
	    maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight());
	}

	// Apply the new width/height Spring. This forces all the
	// components to have the same size.
	for (int i = 0; i < max; i++)
	{
	    SpringLayout.Constraints cons = layout.getConstraints(parent
		    .getComponent(i));

	    cons.setWidth(maxWidthSpring);
	    cons.setHeight(maxHeightSpring);
	}

	// Then adjust the x/y constraints of all the cells so that they
	// are aligned in a grid.
	SpringLayout.Constraints lastCons = null;
	SpringLayout.Constraints lastRowCons = null;
	for (int i = 0; i < max; i++)
	{
	    SpringLayout.Constraints cons = layout.getConstraints(parent
		    .getComponent(i));
	    if (i % cols == 0)
	    { // start of new row
		lastRowCons = lastCons;
		cons.setX(initialXSpring);
	    }
	    else
	    { // x position depends on previous component
		cons.setX(Spring.sum(lastCons.getConstraint(SpringLayout.EAST),
			xPadSpring));
	    }

	    if (i / cols == 0)
	    { // first row
		cons.setY(initialYSpring);
	    }
	    else
	    { // y position depends on previous row
		cons.setY(Spring.sum(lastRowCons
			.getConstraint(SpringLayout.SOUTH), yPadSpring));
	    }
	    lastCons = cons;
	}

	// Set the parent's size.
	SpringLayout.Constraints pCons = layout.getConstraints(parent);
	pCons.setConstraint(SpringLayout.SOUTH, Spring.sum(Spring
		.constant(yPad), lastCons.getConstraint(SpringLayout.SOUTH)));
	pCons.setConstraint(SpringLayout.EAST, Spring.sum(
		Spring.constant(xPad), lastCons
			.getConstraint(SpringLayout.EAST)));
    }

    /* Used by makeCompactGrid. */
    private static SpringLayout.Constraints getConstraintsForCell(int row,
	    int col, Container parent, int cols)
    {
	SpringLayout layout = (SpringLayout) parent.getLayout();
	Component c = parent.getComponent(row * cols + col);
	return layout.getConstraints(c);
    }

    /**
     * Aligns the first <code>rows</code> * <code>cols</code> components of
     * <code>parent</code> in a grid. Each component in a column is as wide as
     * the maximum preferred width of the components in that column; height is
     * similarly determined for each row. The parent is made just big enough to
     * fit them all.
     * 
     * @param rows
     *            number of rows
     * @param cols
     *            number of columns
     * @param initialX
     *            x location to start the grid at
     * @param initialY
     *            y location to start the grid at
     * @param xPad
     *            x padding between cells
     * @param yPad
     *            y padding between cells
     */
    public static void makeCompactGrid(Container parent, int rows, int cols,
	    int initialX, int initialY, int xPad, int yPad)
    {
	SpringLayout layout;
	try
	{
	    layout = (SpringLayout) parent.getLayout();
	}
	catch (ClassCastException exc)
	{
	    System.err
		    .println("The first argument to makeCompactGrid must use SpringLayout.");
	    return;
	}

	// Align all cells in each column and make them the same width.
	Spring x = Spring.constant(initialX);
	for (int c = 0; c < cols; c++)
	{
	    Spring width = Spring.constant(0);
	    for (int r = 0; r < rows; r++)
	    {
		width = Spring.max(width, getConstraintsForCell(r, c, parent,
			cols).getWidth());
	    }
	    for (int r = 0; r < rows; r++)
	    {
		SpringLayout.Constraints constraints = getConstraintsForCell(r,
			c, parent, cols);
		constraints.setX(x);
		constraints.setWidth(width);
	    }
	    x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad)));
	}

	// Align all cells in each row and make them the same height.
	Spring y = Spring.constant(initialY);
	for (int r = 0; r < rows; r++)
	{
	    Spring height = Spring.constant(0);
	    for (int c = 0; c < cols; c++)
	    {
		height = Spring.max(height, getConstraintsForCell(r, c, parent,
			cols).getHeight());
	    }
	    for (int c = 0; c < cols; c++)
	    {
		SpringLayout.Constraints constraints = getConstraintsForCell(r,
			c, parent, cols);
		constraints.setY(y);
		constraints.setHeight(height);
	    }
	    y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad)));
	}

	// Set the parent's size.
	SpringLayout.Constraints pCons = layout.getConstraints(parent);
	pCons.setConstraint(SpringLayout.SOUTH, y);
	pCons.setConstraint(SpringLayout.EAST, x);
    }
}